package dnl.jexem.remote.ssh;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.ethz.ssh2.ChannelCondition;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import dnl.jexem.remote.RemoteSession;
import dnl.jexem.remote.UserPasswordSessionInfo;

public class SshSession extends RemoteSession {

	private static final Logger logger = LoggerFactory.getLogger(SshSession.class.getSimpleName());

	private Connection sshConection;
	private Session sess;
	
	public SshSession(UserPasswordSessionInfo sessionInfo) {
		super(sessionInfo);
	}

	public Connection getSshConection() {
		return sshConection;
	}

	public void connect() throws IOException {
//		if (passwordManager == null) {
//			throw new IllegalStateException("Password Manager not inited.");
//		}
		Connection conn = new Connection(sessionInfo.getHost());
		conn.connect(null, 1500, 0);
		String pass = sessionInfo.getPassword();
//		pass = passwordManager.getPassword(pass);
		conn.authenticateWithPassword(sessionInfo.getUserName(), pass);
		sshConection = conn;
		if (sshConection.isAuthenticationComplete()) {
			connected = true;
		}
	}

	public OngoingSshCommandResult executeOngoingCommand(String command,
			final OutputListener sysoutListener, final OutputListener syserrListener)
			throws IOException {
		if (!connected) {
			connect();
		}
		if (sshConection == null) {
			throw new IllegalStateException("Has no SSH connection.");
		}
		sess = getSession();
		sess.execCommand(command);
		OngoingSshCommandResult result = new OngoingSshCommandResult(sess.getStdout(), sess
				.getStderr());
		result.setSyserrListener(syserrListener);
		result.setSysoutListener(sysoutListener);
		result.startStreamsExtraction();
		return result;
	}

	public SshCommandResult executeCommand(String command) throws IOException {
		if (!connected) {
			connect();
		}
		if (sshConection == null) {
			throw new IllegalStateException("Has no SSH connection.");
		}
		sess = getSession();
		SshCommandResult result = new SshCommandResult();
		sess.execCommand(command);
		sess.waitForCondition(ChannelCondition.EXIT_SIGNAL, 5 * 60 * 1000);
		result.setSysout(extractStream(sess.getStdout()));
		result.setSyserr(extractStream(sess.getStderr()));
		result.setCommand(command);
		result.setExitCode(sess.getExitStatus());
		sess.close();
		// sshConection.close();
		logger.info("Executed remote command using " + sessionInfo.getUserName() + "@"
				+ sessionInfo.getHost() + " >\n" + result.getDescription());
		return result;
	}

	private Session getSession() {

		for (int i = 0; i < 3; i++) {
			try {
				return sshConection.openSession();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}

	private String extractStream(InputStream in) throws IOException {
		StringBuffer sb = new StringBuffer();
		InputStream stdout = new StreamGobbler(in);
		BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
		while (true) {
			String line = br.readLine();
			if (line == null)
				break;
			sb.append(line);
			sb.append("\n");
		}
		return sb.toString();
	}

}
